package cn.galudisu.reactivemanifesto

import akka.actor.SupervisorStrategy.{Escalate, Resume}
import akka.actor.{Actor, ActorLogging, ActorRef, OneForOneStrategy, Props, Terminated}
import akka.http.scaladsl.model.Uri
import akka.stream.ActorMaterializer
import cn.galudisu.reactivemanifesto.GospelCircuitBreaker.Starting
import cn.galudisu.reactivemanifesto.GospelMaster.Cabinet
import cn.galudisu.reactivemanifesto.event.CircuitBreakerBus

import scala.concurrent.duration._
import scala.language.postfixOps

class GospelMaster(eventBus: CircuitBreakerBus)(implicit val mat:ActorMaterializer) extends Actor with ActorLogging {

  import context.dispatcher
  var apis:Set[Uri] = Set.empty

  override val supervisorStrategy: OneForOneStrategy =
    OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
      case _: ArithmeticException ⇒ Resume
      case t ⇒
        super.supervisorStrategy.decider.applyOrElse(t, (_: Any) ⇒ Escalate)
    }

  def breakee: ActorRef = context.actorOf(Props.create(classOf[GospelCircuitBreaker], apis, eventBus, mat))


  override def preStart(): Unit = {
    import GospelConfig._
    context.system.scheduler.schedule(initial_deplay seconds,
      interval seconds,
      self,
      Starting)

  }

  override def receive: Receive = {
    case start@ Starting =>
      context watch breakee
      breakee.forward(start)

    // 更新条目
    case cab : Cabinet =>
      apis ++= cab.uri

    case Terminated(child:ActorRef) =>
      log.debug("{} has finish its job", child.path)
  }
}

object GospelMaster {
  case class Cabinet(uri: Set[Uri])
}
